package controllers;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.Query;

import models.BadgeType;
import models.Comment;
import models.Handshake;
import models.Handshake.Status;
import models.Offer;
import models.Request;
import models.Notification;
import models.User;
import play.db.jpa.JPA;
import play.mvc.With;
// Require Login
@With(Secure.class)
public class Handshakes extends BaseController
{
    public static void bindToOffer(Long id) {
        User user = getConnectedUser();
    	Offer offer = Offer.findById(id);

        Request request = new Request(user, offer);
        request.title = "REQUEST FOR: " + offer.title;
		request.isAutoGenerated = true;

    	Handshake handshakeItem = new Handshake();
        handshakeItem.status = Status.WAITING_APPROVAL;
    	handshakeItem.offer = offer;
    	handshakeItem.request = request;
    	handshakeItem.creationDate = new Date();

	handshakeItem.requesterId = request.user.id;
	handshakeItem.offererId = offer.user.id;
	
	handshakeItem.checkOriginallyAnOffer = true;
	handshakeItem.offererStart = false;
	handshakeItem.requesterStart = false;
	handshakeItem.offererVoted = false;
	handshakeItem.requesterVoted = false;
	handshakeItem.typeOfVoteOfferer = -1;
	handshakeItem.typeOfVoteRequester = -1;
	
	/*
	Kutay Ozdogru
	To notify offerer, we are recording it
	*/

	
	offer.save();
	request.save();
    handshakeItem.save();
	Notification notificationItem = new Notification(offer,offer.user,handshakeItem,"");
	notificationItem.save();
	Boolean created = true;
    	renderTemplate("Handshakes/bind.html", handshakeItem, created);
    }

    public static void cancelApplication(Long handshakeId) {
	Handshake handshakeItem = Handshake.findById(handshakeId);

	/*
	Kutay Ozdogru Fix start for Issue-4
	If we would like to cancel application we also should remove notification
	*/
	
	Query cancelledHandshakeQuery = JPA.em().createQuery("from " + Notification.class.getName() + " where handshake_id=" + handshakeId);
	List<Object[]> cancelledList = cancelledHandshakeQuery.getResultList();
	List<Notification> cancelledHandshakes = new ArrayList(cancelledList);
	for (Notification cancelled : cancelledHandshakes)
	{
		cancelled.delete();
	}	
	
	Query cancelledRequestQuery = JPA.em().createQuery("from " + Request.class.getName() + " where id=" + handshakeItem.request.id);
	List<Object[]> cancelledList2 = cancelledRequestQuery.getResultList();
	List<Request> cancelledRequests = new ArrayList(cancelledList2);
	for (Request cancelled : cancelledRequests)
	{
		cancelled.delete();
	}	
	/*
	Kutay Ozdogru Fix end for Issue-4
	*/
	handshakeItem.delete();
	Boolean cancelled = true;
	renderTemplate("Handshakes/bind.html", cancelled);
    }

    public static void bindToRequest(Long id) {
	User user = getConnectedUser();
	Request request = Request.findById(id);

	Offer offer = new Offer(user, request);
	offer.isAutoGenerated = true;
	
	//offer.credit = request.credit; credit honey comb is deleted
	
	offer.title = "OFFER FOR: " + request.title;
	offer.save();

	Handshake handshakeItem = new Handshake();
	handshakeItem.status = Status.WAITING_APPROVAL;
	handshakeItem.offer = offer;
	handshakeItem.request = request;
	handshakeItem.creationDate = new Date();

	handshakeItem.requesterId = request.user.id;
	handshakeItem.offererId = offer.user.id;

	handshakeItem.checkOriginallyAnOffer = false;
	handshakeItem.offererStart = false;
	handshakeItem.requesterStart = false;
	handshakeItem.offererVoted = false;
	handshakeItem.requesterVoted = false;
	handshakeItem.typeOfVoteOfferer = -1;
	handshakeItem.typeOfVoteRequester = -1;
	handshakeItem.save();
	
	/*
	Kutay Ozdogru
	To notify requester, we are recording it
	*/
	Notification notificationItem = new Notification(request,request.user, handshakeItem, "");
	notificationItem.save();
	
	
	

	Boolean created = true;
	renderTemplate("Handshakes/bind.html", handshakeItem, created);
    }

    public static void show(Long id) {
	User currentUser = getConnectedUser();
	Handshake handshake = Handshake.findById(id);
	List<Comment> comments = Comment.find("handshake = ?", handshake).fetch();
	Boolean originallyOffer = handshake.checkOriginallyAnOffer;
	Integer commentCount = comments.size();
	//Is current user voted on the current handshake?
	Boolean didIVoted = false;
	//If is current user voted on the current handshake, then what did the user vote?
	String whatDidIVote = "";
	
	/*
	Kutay Ozdogru Fix start for issue-36
	Only accepted and nonvoted handshakes can use vote functionality
	*/
	Boolean canIVote = false;
	
	if( handshake.status == Status.ACCEPTED || handshake.status == Status.NOTVOTED )
	{
		canIVote = true;
	}
	
	/*
	Kutay Ozdogru Fix end for issue-36
	Only accepted and nonvoted handshakes can use vote functionality
	*/	

	if(currentUser.id == handshake.offer.user.id)
	{
		if( handshake.offererVoted )
		{
			didIVoted = true;
			
			if( handshake.typeOfVoteOfferer == 0 )
			{
				whatDidIVote = "NEGATIVE";
			}
			else if( handshake.typeOfVoteOfferer == 1 )
			{
				whatDidIVote = "POSITIVE";
			}
			
		}
	}
    else if(currentUser.id == handshake.request.user.id)
	{
		if( handshake.requesterVoted )
		{
			didIVoted = true;
			
			if( handshake.typeOfVoteRequester == 0 )
			{
				whatDidIVote = "NEGATIVE";
			}
			else if( handshake.typeOfVoteRequester == 1 )
			{
				whatDidIVote = "POSITIVE";
			}
		}
	}
	
	User offerer = User.findById(handshake.offererId);
	User requester = User.findById(handshake.requesterId);
	Boolean handshakeParticipant = ((currentUser == offerer) || (currentUser == requester));
	
	Query notificationQuery =
	JPA.em().createQuery("from " + Notification.class.getName() + " where handshake.id=" + handshake.id + " and status='SHOW' and user.id=" + currentUser.id + " and handshake.status != 'ACCEPTED'");
	List<Object[]> notificationList = notificationQuery.getResultList();
	List<Notification> nonShowNotifications = new ArrayList(notificationList);
	
	for (Notification nitems : nonShowNotifications) {
	    nitems.status = Notification.Statuses.NOTSHOW;
	    nitems.save();
	}
	
	render(currentUser, handshake, comments, originallyOffer, commentCount, handshakeParticipant, didIVoted, whatDidIVote, canIVote);
    }

    public static void list() {
        User user = getConnectedUser();
        List<Handshake> handshakes = Handshake.find("(offer.user.id = ? or request.user.id = ?) and (status!='WAITING_APPROVAL' and status!='IGNORED' and status!='REJECTED')", user.id, user.id).fetch();
        render(handshakes);
    }
 
    public static void search(String phrase) {
        User user = getConnectedUser();

        List<Handshake> allHandshakes = Handshake.findAll();

        render(user, allHandshakes, phrase);
    }

    public static void accept(Long handshakeId) {
        Handshake handshakeItem = Handshake.findById(handshakeId);
        handshakeItem.status = Status.ACCEPTED;
        handshakeItem.save();

		// Kutay - Cem
		
		
		/*
			Kutay Ozdogru - FIX start for Issue-25
			Here we should analyze if this handshake;
			A-Bind for offer
			OR
			B-Bind to request
			
			If A, then we should increase connected user's services given and other user's services taken
			If B, then we should increase connected user's services taken abd other user's services given 
		*/
		if( handshakeItem.checkOriginallyAnOffer )
		{
			User user = getConnectedUser();
			user.servicesGiven++;
			user.save();
			
			User secondUser = handshakeItem.request.user;
			secondUser.servicesTaken++;
			secondUser.save();
		}
		else
		{
			User user = getConnectedUser();
			user.servicesTaken++;
			user.save();
			
			User secondUser = handshakeItem.offer.user;
			secondUser.servicesGiven++;
			secondUser.save();
		}
		/*
			Kutay Ozdogru - FIX end for Issue-25
	
		*/	
	Offer offer = Offer.findById(handshakeItem.offer.id);
	offer.status = Offer.Status.HANDSHAKED;
	offer.save();
	

	Request request = Request.findById(handshakeItem.request.id);
	request.status = Request.Status.HANDSHAKED;
    request.save();

	/*
	Kutay Ozdogru
	To notify both offerer and requester, we are recording them
	*/
	Notification notificationItem1 = new Notification(handshakeItem, handshakeItem.request.user,"");
	notificationItem1.save();
	Notification notificationItem2 = new Notification(handshakeItem, handshakeItem.offer.user,"");
	notificationItem2.save();	
	
	
	/* mark applications which were not accepted as obsolete 
	
	If more than one person applied to one offer then two notifications are being listed for the offerer
	so offerer is going to select one of requests or ignore both
	
	The following case is; when offerer accepts one of requests then the other should be rejected automatically
	*/
	Query rejectedHandshakeQuery =
	JPA.em().createQuery("from " + Handshake.class.getName() +
	" where offer_id=" + handshakeItem.offer.id + " and request_id!=" + handshakeItem.request.id + " and status !='IGNORED'");
	List<Object[]> rejectedList = rejectedHandshakeQuery.getResultList();
	List<Handshake> rejectedHandshakes = new ArrayList(rejectedList);
	for (Handshake rejected : rejectedHandshakes)
	{
	    rejected.status = Status.REJECTED;
	    rejected.save();
		
		Notification notificationItem3 = new Notification(rejected, rejected.request.user,"");
		notificationItem3.save();		
		
	}
	
	Boolean accepted = true;
        renderTemplate("Handshakes/bind.html", handshakeItem, accepted);
    }

    
    public static void ignore(Long handshakeId, String reasonText) {
	Handshake handshakeItem = Handshake.findById(handshakeId);
	handshakeItem.status = Status.IGNORED;
	handshakeItem.save();
	Boolean isRequesterIgnored = false;
	
	if( handshakeItem.checkOriginallyAnOffer )
	{
		isRequesterIgnored = true;
	}

	/*
	Kutay Ozdogru
	To notify requester for IGNORE  we are recording it
	but we first change status of previous notification
	*/

	Query notificationQuery = JPA.em().createQuery("from " + Notification.class.getName() + " where handshake.id=" + handshakeItem.id + " and status='SHOW'");
	List<Object[]> notificationList = notificationQuery.getResultList();
	List<Notification> nonShowNotifications = new ArrayList(notificationList);
	
	for (Notification nitems : nonShowNotifications) {
	    nitems.status = Notification.Statuses.NOTSHOW;
	    nitems.save();
	}
	if( isRequesterIgnored )
	{
		Notification notificationItem = new Notification(handshakeItem, handshakeItem.request.user, reasonText);
		notificationItem.save();
	}
	else
	{
		Notification notificationItem = new Notification(handshakeItem, handshakeItem.offer.user, reasonText);
		notificationItem.save();
	}
	
	
	
	renderTemplate("Handshakes/reject.html", handshakeItem);
    }

	
	/*
	When user applies any offer then he/she may want to cancel
	in this condition the following function is being called
	
	before handshake state becomes accepted
	*/
	public static void removeMyOwnRequestOnOffer(Long handshakeId) {
	
	Handshake handshakeItem = Handshake.findById(handshakeId);
	Handshake tempHandshakeItem = handshakeItem;
	Query notificationQuery = JPA.em().createQuery("from " + Notification.class.getName() + " where handshake.id=" + handshakeItem.id + " and status='SHOW'");
	List<Object[]> notificationList = notificationQuery.getResultList();
	List<Notification> nonShowNotifications = new ArrayList(notificationList);
	
	for (Notification nitems : nonShowNotifications) {
	    nitems.delete();
	}
	
	
	handshakeItem.delete();
	
	Query requestQuery = JPA.em().createQuery("from " + Request.class.getName() + " where id=" + tempHandshakeItem.request.id + " AND user_id=" + tempHandshakeItem.requesterId);
	
	List<Object[]> requestList = requestQuery.getResultList();
	List<Request> requests = new ArrayList(requestList);
	
	for (Request nitems2 : requests) {
	    nitems2.delete();
	}
	
	renderTemplate("Handshakes/bind.html");
    }
	
	/*
	When user applies any offer on request then he/she may want to cancel
	in this condition the following function is being called
	
	before handshake state becomes accepted
	*/
	public static void removeMyOwnOfferOnRequest(Long handshakeId) {
	
	Handshake handshakeItem = Handshake.findById(handshakeId);
	Handshake tempHandshakeItem = handshakeItem;
	
	Query notificationQuery = JPA.em().createQuery("from " + Notification.class.getName() + " where handshake.id=" + handshakeItem.id + " and status='SHOW'");
	List<Object[]> notificationList = notificationQuery.getResultList();
	List<Notification> nonShowNotifications = new ArrayList(notificationList);
	
	for (Notification nitems : nonShowNotifications) {
	    nitems.delete();
	}
	
	handshakeItem.delete();
	
	Query offerQuery = JPA.em().createQuery("from " + Offer.class.getName() + " where id=" + tempHandshakeItem.offer.id + " AND user_id=" + tempHandshakeItem.offererId);
	
	List<Object[]> offerList = offerQuery.getResultList();
	List<Offer> offers = new ArrayList(offerList);
	
	for (Offer nitems3 : offers) {
	    nitems3.delete();
	}
	
	renderTemplate("Handshakes/bind.html");
    }    
    public static void start(Long handshakeId) {
        Handshake handshakeItem = Handshake.findById(handshakeId);

	Boolean startedByBoth, startedByOne;
	
	User user = getConnectedUser();
	if (user.id == handshakeItem.offererId) {
	    handshakeItem.offererStart = true;
	} else if (user.id == handshakeItem.requesterId) {
	    handshakeItem.requesterStart = true;
	}
        handshakeItem.save();

	startedByOne = (handshakeItem.offererStart || handshakeItem.requesterStart);
	startedByBoth = (handshakeItem.offererStart && handshakeItem.requesterStart);
	
	/*we dont use start end button any more
	 * if (startedByBoth) {
	    User offerer = User.findById(handshakeItem.offererId);
	    User requester = User.findById(handshakeItem.requesterId);
	    offerer.balance += handshakeItem.offer.credit;
	    requester.balance -= handshakeItem.offer.credit;
	    offerer.save();
	    requester.save();
	    handshakeItem.status = Status.STARTED;
	    handshakeItem.save();
	}*/

        renderTemplate("Handshakes/bind.html", handshakeItem, startedByBoth, startedByOne);
    }
    
	
	/*
	This function is being called after handshake accepted, when one of the parties want to cancel application
	*/
    public static void cancel(Long handshakeId) {
        Handshake handshake = Handshake.findById(handshakeId);
        handshake.status = Status.CANCELLED;
        handshake.save();
		
		/*
			Kutay Ozdogru - FIX start for Issue-6
			Now we should notify the other party and remove notification
			for the accept status
		*/
	Query notificationQuery = JPA.em().createQuery("from " + Notification.class.getName() + " where handshake.id=" + handshakeId + " and status='SHOW'");
	List<Object[]> notificationList = notificationQuery.getResultList();
	List<Notification> nonShowNotifications = new ArrayList(notificationList);
	
	for (Notification nitems : nonShowNotifications) {
	    nitems.status = Notification.Statuses.NOTSHOW;
	    nitems.save();
	}
        User user = getConnectedUser();

		//If the requester cancels handshake then we should notify offerer
        if(user.id == handshake.request.user.id)
		{
			Notification notificationItem = new Notification(handshake, handshake.offer.user,"");
			notificationItem.save();	

		}
		//If the offerer cancels handshake then we should notify requester
        else if(user.id == handshake.offer.user.id )
		{
			Notification notificationItem = new Notification(handshake, handshake.request.user,"");
			notificationItem.save();	
		}		
	
		
		/*
			Kutay Ozdogru - FIX end for Issue-6
		*/
		
		
		/*
			Kutay Ozdogru - FIX start for Issue-9
			If one of parties cancel the current handshake then we should update
			servicesTaken for requester and servicesGiven for offerer
		*/
		
		User offerParty = handshake.offer.user;
		if( offerParty.servicesGiven > 0)
		{
			offerParty.servicesGiven--;
			offerParty.save();
		}
		
		User requestParty = handshake.request.user;
		if( requestParty.servicesTaken > 0)
		{
			requestParty.servicesTaken--;
			requestParty.save();
		}
	
		/*
			Kutay Ozdogru - FIX end for Issue-9

		*/


		
        show(handshakeId);
    }
    
    public static void end(Long handshakeId) {

	
        Handshake handshake = Handshake.findById(handshakeId);
        if(handshake.offererVoted == false && handshake.requesterVoted == false)
        {
        	handshake.status = Status.NOTVOTED;
        	handshake.save();
        	show(handshakeId);
        }
        else if( handshake.offererVoted == true && handshake.requesterVoted == true )
        {
	        handshake.status = Status.DONE;
	        handshake.save();
	        updateBadgeForHandshake(handshake);
	        
	        show(handshakeId);
        }
		else if( (handshake.offererVoted == false && handshake.requesterVoted == true) || (handshake.offererVoted == true && handshake.requesterVoted == false) )
		{
			handshake.status = Status.NOTVOTED;
        	handshake.save();
        	show(handshakeId);
		}
    }

    public static void saveComment(Long handshakeId)
    {  	
        User user = getConnectedUser();
        Comment comment = new Comment();
        comment.user = user;
        comment.handshake = Handshake.findById(handshakeId);
        comment.date = new Date();
        comment.text = request.params.get("message");
        comment.save();

		
		/*
			Kutay Ozdogru - FIX start for Issue-10
		*/

		//If the requester  make comment on handshake then we should notify offerer
        if(user.id == comment.handshake.request.user.id)
		{
			Notification notificationItem = new Notification(comment, comment.handshake.offer.user,"");
			notificationItem.save();	

		}
		//If the offerer make comment on handshake then we should notify requester
        else if(user.id == comment.handshake.offer.user.id )
		{
			Notification notificationItem = new Notification(comment, comment.handshake.request.user,"");
			notificationItem.save();	
		}		
		/*
			Kutay Ozdogru - FIX end for Issue-10
		*/		
		show(handshakeId);
    }
	public static void showNotification(Long notificationId)
	{
		/*
			Kutay Ozdogru - FIX start for Issue-10
		*/

		List<Notification> notificationItems  =  Notification.find("type='Commentt' AND id=" + notificationId).fetch();
		
		// When user check his/her notifications then we do not need to list them ;)
		for (Notification nitems : notificationItems) {
			nitems.status = Notification.Statuses.NOTSHOW;
			nitems.save();
		}
		renderTemplate("Handshakes/showcomment.html", notificationItems);
		

		/*
			Kutay Ozdogru - FIX end for Issue-10
		*/
		
	}
	
    public static void vote_pos(Long handshakeId)
    {
		/*
		Kutay Ozdogru
		
		If one of parties gives a positive vote on handshake
		
		Initially: ( when create a new handshake in bind2request or bind2offer
		----------
		typeOfVoteOfferer = -1;
		typeOfVoteRequester = -1;
		
		If vote is positive then set 1
		If vote is negative then set 0
		If notvoted, it should stay -1 as its initial value
		*/
        User user = getConnectedUser();
        User secondUser;
		int number = 0;
    	Handshake handshake = Handshake.findById(handshakeId);
		
        if(user.id == handshake.offer.user.id)
		{
			handshake.offererVoted = true;
			handshake.typeOfVoteOfferer = 1;
        	secondUser = User.findById(handshake.request.user.id);
		}
        else
		{
			handshake.requesterVoted = true;
			handshake.typeOfVoteRequester = 1;
        	secondUser = User.findById(handshake.offer.user.id);
		}
		

		number = secondUser.vote_pos_num;
		secondUser.vote_pos_num = number + 1;
		secondUser.save();
		
		
		//After this, handshale status will be handled
        if(handshake.offererVoted == false && handshake.requesterVoted == false)
        {
        	handshake.status = Status.NOTVOTED;
        	handshake.save();
        	show(handshakeId);
        }
        else if( handshake.offererVoted == true && handshake.requesterVoted == true )
        {
	        handshake.status = Status.DONE;
	        handshake.save();
	        updateBadgeForHandshake(handshake);
	        
	        show(handshakeId);
        }
		else if( (handshake.offererVoted == false && handshake.requesterVoted == true) || (handshake.offererVoted == true && handshake.requesterVoted == false) )
		{
			handshake.status = Status.NOTVOTED;
        	handshake.save();
        	show(handshakeId);
		}


        handshake.save();
        Users.update_credit(secondUser.id, handshake.id);
    	show(handshakeId);
    }
    public static void vote_neg(Long handshakeId)
    {
		/*
		Kutay Ozdogru
		
		If one of parties gives a negative vote on handshake
		*/
        User user = getConnectedUser();
        User secondUser;
    	Handshake handshake = Handshake.findById(handshakeId);
		int number = 0;
		
        if(user.id == handshake.offer.user.id)
		{
			handshake.offererVoted = true;
			handshake.typeOfVoteOfferer = 0;
        	secondUser = User.findById(handshake.request.user.id);
		}
        else
		{
			handshake.requesterVoted = true;
			handshake.typeOfVoteRequester = 0;
        	secondUser = User.findById(handshake.offer.user.id);
		}
		
		number = secondUser.vote_neg_num;
		secondUser.vote_neg_num = number + 1;
		secondUser.save();
		
		//After this, handshale status will be handled		
        if(handshake.offererVoted == false && handshake.requesterVoted == false)
        {
        	handshake.status = Status.NOTVOTED;
        	handshake.save();
        	show(handshakeId);
        }
        else if( handshake.offererVoted == true && handshake.requesterVoted == true )
        {
	        handshake.status = Status.DONE;
	        handshake.save();
	        updateBadgeForHandshake(handshake);
	        
	        show(handshakeId);
        }
		else if( (handshake.offererVoted == false && handshake.requesterVoted == true) || (handshake.offererVoted == true && handshake.requesterVoted == false) )
		{
			handshake.status = Status.NOTVOTED;
        	handshake.save();
        	show(handshakeId);
		}
		
        handshake.save();
        Users.update_credit(secondUser.id, handshake.id);
    	show(handshakeId);
    }
    
    private static void updateBadgeForHandshake(Handshake handshake){
    	updateBadgeForUser(handshake.offer.user);
    	updateBadgeForUser(handshake.request.user);
    }

    private static void updateBadgeForUser(User user){
    	Date now = new Date();
    	Timestamp sixMonthAgo = new Timestamp(now.getTime() - 86400000*30*6);

    	long count=Handshake.count("(offer.user.id = ? or request.user.id = ?) and creationDate> ?", user.id, user.id,sixMonthAgo);
    	user.badge=BadgeType.NEW_BEE;
    	if(count>=5)
    		user.badge=BadgeType.BUSY_BEE;
    	if(count>=30)
    		user.badge=BadgeType.WORKING_BEE;
    	if(count>=60)
    		user.badge=BadgeType.BUMBLE_BEE;
    	user.save();
    	
    }
}
